/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2018-2023.
 * Description: init task_struct extend support add new member
 * Author: nixiaoming
 * Create: 2018-2-13
 */

#include <linux/task_struct_extend.h>
#ifdef CONFIG_RTOS_KBOX
#include <linux/set_kbox_region.h>
#endif
#ifdef CONFIG_RTOS_SWXN
#include <internal/rtos_swxn.h>
#endif
#ifdef CONFIG_RTOS_MEM_KSM_ADD
#include <linux/rtos_ksm_add.h>
#endif

#ifdef CONFIG_RTOS_HAL_HPVISOR_VNOTIFY
#include "../virt/hpvisor/vnotify.h"
#endif

#include <linux/slab.h>

#ifdef CONFIG_RTOS_HKIDS
#include <linux/hkids/hkids_path.h>
static struct hkids_path_struct hkids_init_path = {
	.ref = REFCOUNT_INIT(1),
	.path = NULL
};
#endif

struct vendor_task init_vendor_task = {
#ifdef CONFIG_RTOS_KBOX
	.kbox_region_conf = ATOMIC_INIT(PROCESS_CONTEXT | KBOX_DEFAULT_REG_ID),
#endif
#ifdef CONFIG_RTOS_ILOCKDEP
	.ilockdep_lock = &ilockdep_init_task,
#endif
#ifdef CONFIG_RTOS_MICROSTATE_ACCT
	.microstates = &microstate_init_task,
#endif
#ifdef CONFIG_RTOS_SWXN
	.swxn = SWXN_DISABLE,
#endif
#ifdef CONFIG_RTOS_MEM_KSM_ADD
	.ksm_add_flag = DISABLE_ALL_PROCESS,
#endif
#ifdef CONFIG_RTOS_HAL_HPVISOR_VNOTIFY
	.chns = &vnotify_init_chns,
#endif
#ifdef CONFIG_RTOS_HKIDS
	.hkids_path = &hkids_init_path,
#endif
};
EXPORT_SYMBOL_NS(init_vendor_task, HUAWEI_NS);

/* only called by copy_process after check task != NULL */
int vendor_task_init(const unsigned long flags, struct task_struct *task)
{
	int retval = 0;
	struct vendor_task *vendor = task_to_vendor_task(task);

	memset(vendor, 0, sizeof(struct vendor_task));
#ifdef CONFIG_RTOS_KBOX
	init_kbox_region(task);
#endif
#ifdef CONFIG_RTOS_DEBUG_SOFTLOCKUP
	softlockup_locking_init(task);
#endif
#ifdef CONFIG_RTOS_SWXN
	init_pid_swxn(task);
#endif
#ifdef CONFIG_RTOS_ILOCKDEP
	vendor->ilockdep_lock = kmem_cache_alloc(ilockdep_cachep, GFP_KERNEL);
	if (!vendor->ilockdep_lock)
		return -ENOMEM;
	ilockdep_init(vendor->ilockdep_lock);
#endif
#ifdef CONFIG_RTOS_MICROSTATE_ACCT
	vendor->microstates = kmem_cache_alloc(microstates_struct_cachep, GFP_KERNEL);
	/* if failed, copy_process will call free_task to free ilockdep_lock */
	if (!vendor->microstates)
		return -ENOMEM;
	msa_init(task);
#endif
#ifdef CONFIG_RTOS_HKIDS
	retval = copy_hkids_path(flags, task);
#endif
	return retval;
}

void set_vendor_member_to_null(struct task_struct *tsk)
{
#if defined(CONFIG_RTOS_ILOCKDEP) || defined(CONFIG_RTOS_MICROSTATE_ACCT) || \
	defined(CONFIG_RTOS_HKIDS)
	struct vendor_task *vendor = task_to_vendor_task(tsk);
#endif
#ifdef CONFIG_RTOS_ILOCKDEP
	vendor->ilockdep_lock = NULL;
#endif
#ifdef CONFIG_RTOS_MICROSTATE_ACCT
	vendor->microstates = NULL;
#endif
#ifdef CONFIG_RTOS_HKIDS
	vendor->hkids_path = NULL;
#endif
}

void free_task_struct_extend_member(struct task_struct *tsk)
{
	struct vendor_task *vendor = task_to_vendor_task(tsk);
#ifdef CONFIG_RTOS_ILOCKDEP
	if (vendor->ilockdep_lock != NULL)
		kmem_cache_free(ilockdep_cachep, vendor->ilockdep_lock);
#endif
#ifdef CONFIG_RTOS_MICROSTATE_ACCT
	if (vendor->microstates != NULL)
		kmem_cache_free(microstates_struct_cachep, vendor->microstates);
#endif
#ifdef CONFIG_RTOS_HKIDS
	free_hkids_path(vendor->hkids_path);
#endif
	memset(vendor, 0, sizeof(struct vendor_task));
}
